#####################################################################
#                                                                   #
#  THIS IS A SOURCE CODE FILE FROM A PROGRAM TO INTERACT WITH THE   #
# LBRY PROTOCOL ( lbry.com ). IT WILL USE THE LBRY SDK ( lbrynet )  #
# FROM THEIR REPOSITORY ( https://github.com/lbryio/lbry-sdk )      #
# WHICH I GONNA PRESENT TO YOU AS A BINARY. SINCE I DID NOT DEVELOP #
# IT AND I'M LAZY TO INTEGRATE IN A MORE SMART WAY. THE SOURCE CODE #
# OF THE SDK IS AVAILABLE IN THE REPOSITORY MENTIONED ABOVE.        #
#                                                                   #
#      ALL THE CODE IN THIS REPOSITORY INCLUDING THIS FILE IS       #
# (C) J.Y.Amihud and Other Contributors 2021. EXCEPT THE LBRY SDK.  #
# YOU CAN USE THIS FILE AND ANY OTHER FILE IN THIS REPOSITORY UNDER #
# THE TERMS OF GNU GENERAL PUBLIC LICENSE VERSION 3 OR ANY LATER    #
# VERSION. TO FIND THE FULL TEXT OF THE LICENSE GO TO THE GNU.ORG   #
# WEBSITE AT ( https://www.gnu.org/licenses/gpl-3.0.html ).         #
#                                                                   #
# THE LBRY SDK IS UNFORTUNATELY UNDER THE MIT LICENSE. IF YOU ARE   #
# NOT INTENDING TO USE MY CODE AND JUST THE SDK. YOU CAN FIND IT ON #
# THEIR OFFICIAL REPOSITORY ABOVE. THEIR LICENSE CHOICE DOES NOT    #
# SPREAD ONTO THIS PROJECT. DON'T GET A FALSE ASSUMPTION THAT SINCE #
# THEY USE A PUSH-OVER LICENSE, I GONNA DO THE SAME. I'M NOT.       #
#                                                                   #
# THE LICENSE CHOSEN FOR THIS PROJECT WILL PROTECT THE 4 ESSENTIAL  #
# FREEDOMS OF THE USER FURTHER, BY NOT ALLOWING ANY WHO TO CHANGE   #
# THE LICENSE AT WILL. SO NO PROPRIETARY SOFTWARE DEVELOPER COULD   #
# TAKE THIS CODE AND MAKE THEIR USER-SUBJUGATING SOFTWARE FROM IT.  #
#                                                                   #
#####################################################################

import os
import urllib.request
import threading
import json

from subprocess import *
from gi.repository import Gtk
from gi.repository import Gdk
from gi.repository import Pango
from gi.repository import GdkPixbuf
from PIL import Image, ImageSequence

from flbry import markdown
from flbry import data_view
from flbry import ui

def resolve(w, win, outbox, url):
    
    # This function will draw a widget of rsolved url

    out = check_output(["flbry/lbrynet",
                         "resolve", url])
    raw_data = out.decode("utf-8")
    
    # Now we want to parse the json

    try:
        out = json.loads(out)
        out = out[url]
    except:
        print("Resolve Failed")
        return False

    is_channel = "value_type" in out and out["value_type"] == "channel"
    percentage = downloaded(out["claim_id"])
    
    # make sure the url path starts with lbry://
    if not url.startswith("lbry://"):
        url = "lbry://"+url
        win.url.set_text(url)

    
    box = Gtk.HBox()

    #### THUMBNAIL ###

    thumb = ""
    try:
        thumb = out["value"]["thumbnail"]["url"]
    except Exception as e:
        print("Error loading thumbnail: ", e)
    

    def thumb_open(w):
        os.system("xdg-open /tmp/flbry_thumbnail")
    
    thumb_button = Gtk.Button()
    thumb_button.set_tooltip_text(thumb)
    if is_channel:
        thumb_image = ui.load(win, ui.net_image, thumb, 150, "/tmp/flbry_thumbnail", True)
    else:
        thumb_image = ui.load(win, ui.net_image, thumb, 400,  "/tmp/flbry_thumbnail", True)
    thumb_button.add(thumb_image)
    thumb_button.set_relief(Gtk.ReliefStyle.NONE)
    thumb_button.connect("clicked", thumb_open)
    
    box.pack_start(thumb_button, False, False, False)
    outbox.pack_start(box, False, False, False)

    from_right_to_thumbnail = Gtk.VBox()
    box.pack_end(from_right_to_thumbnail, True, True, False)

    # If channel load banner
    if is_channel:
        if "cover" in out["value"]:
            channel_banner = ui.load(win, ui.net_image, out["value"]["cover"]["url"], False, "", True)
            channel_scroll = Gtk.ScrolledWindow()
            channel_scroll.set_size_request(400,150)
            channel_scroll.add_with_viewport(channel_banner)
            from_right_to_thumbnail.pack_start(channel_scroll, False, False, False)
        else:
            try:
                channel_scroll.destroy()
            except:
                pass
            
    
    #### NAME / CHANNEL ####

    the_packing_box = from_right_to_thumbnail
    if is_channel:
        the_packing_box = outbox
    
    name_channel_box = Gtk.VBox()
    the_packing_box.pack_start(name_channel_box, False, False, False)

    # Channel

    if "signing_channel" in out:

        # Get channel name
        try:
            channel_name = out["signing_channel"]["value"]["title"]
        except:
            channel_name = out["signing_channel"]["name"]

        def channel_resolve(w):
            win.url.set_text(out["signing_channel"]["canonical_url"])
            win.url.activate()
            
        channel_button = Gtk.Button()
        channel_button.set_tooltip_text(out["signing_channel"]["canonical_url"])
        channel_button.connect("clicked", channel_resolve)
        channel_button.set_relief(Gtk.ReliefStyle.NONE)
        channel_button_box = Gtk.HBox()
        channel_button.add(channel_button_box)

        # If channel thumbnail exists.
        try:
            channel_thumb = ui.load(win, ui.net_image, out["signing_channel"]["value"]["thumbnail"]["url"], 40 , "", False)
            channel_button_box.pack_start(channel_thumb, False,False,False)
        except:
            pass
        
        channel_button_box.pack_start(Gtk.Label(channel_name), False, False, False)
        name_channel_box.pack_start(channel_button,False,False,False)
    
    # name it self
    title = "[no title]"
    try:
        title = out["value"]["title"]
    except:
        pass
    title_label = Gtk.Label()
    title_label.set_line_wrap_mode( Gtk.WrapMode.WORD )
    title_label.set_line_wrap(True)
    title_label.set_markup('<span size="x-large">  '+title+'</span> ')
    title_label.set_selectable(True)
    title_label.set_css_name("")
    name_channel_box.pack_start(title_label, False, False, False)

    ################# TOOL BAR ##################


    toolbox = Gtk.HBox()
    the_packing_box.pack_start(toolbox, False, False,False)

    if not is_channel:

        def download_action(w):
            start_downloading(out["permanent_url"])
        
        download_button = Gtk.Button()
        download_button.connect("clicked", download_action)
        download_button.set_relief(Gtk.ReliefStyle.NONE)
        download_box = Gtk.HBox()
        download_button.add(download_box)
        download_icon = ui.icon(win, "download")
        download_box.pack_start(download_icon, False, False, False)
        download_box.pack_start(Gtk.Label("Download"), False, False, False)
        toolbox.pack_start(download_button, False,False,False)

        download_bar = Gtk.ProgressBar()
        the_packing_box.pack_start(download_bar, False, False,False)

        def delete_action(w):
            filename = get_downloaded_file(out["claim_id"])
            delete_file(out["claim_id"])

            try:
                os.remove(filename)
            except:
                pass
            
        delete_button = Gtk.Button()
        delete_button.connect("clicked", delete_action)
        delete_button.set_relief(Gtk.ReliefStyle.NONE)
        delete_box = Gtk.HBox()
        delete_button.add(delete_box)
        delete_icon = ui.icon(win,"delete")
        delete_box.pack_start(delete_icon, False, False, False)
        delete_box.pack_start(Gtk.Label("Delete"), False, False, False)
        toolbox.pack_start(delete_button, False,False,False)

        def launch_action(w):
            Popen(["xdg-open", get_downloaded_file(out["claim_id"])])

        launch_button = Gtk.Button()
        launch_button.connect("clicked", launch_action)
        launch_button.set_relief(Gtk.ReliefStyle.NONE)
        launch_box = Gtk.HBox()
        launch_button.add(launch_box)
        launch_icon = ui.icon(win, "launch")
        launch_box.pack_start(launch_icon, False, False, False)
        launch_box.pack_start(Gtk.Label("Launch"), False, False, False)
        toolbox.pack_start(launch_button, False,False,False)

        win.check_download_daemon_keep_alive = True
        
        t = threading.Thread(target=downloading_check_thread, args=(win, out["claim_id"],download_button, delete_button, launch_button, download_bar))
        t.setDaemon(True)
        t.start()
        def kill_daemon(w):
            win.check_download_daemon_keep_alive = False
        download_button.connect("destroy", kill_daemon)
    
    ########### BOTTOM NOTEBOOK ##############

    notebook = Gtk.Notebook()
    outbox.pack_start(notebook, True, True,False)

    # If article read article
    try:
        if out["value"]["source"]["media_type"] == "text/markdown":
            playout = check_output(["flbry/lbrynet",
                                        "get", url])
            # Parsing the Json
            playout = json.loads(playout)

            md_text = open(playout['download_path'])
            md_text = md_text.read()

            # Markdown covenreted
            md_scrl = Gtk.ScrolledWindow()
            md_view = Gtk.TextView()
            md_view.set_wrap_mode(Gtk.WrapMode.WORD )
            md_buffer = md_view.get_buffer()
            md_view.set_editable(False)
            md_scrl.add(md_view)
            md_buffer.set_text(md_text)
            markdown.convert(win, md_view)

            notebook.append_page(md_scrl, Gtk.Label("Read Article"))

            # Markdown source
            md_scrl = Gtk.ScrolledWindow()
            md_view = Gtk.TextView()
            #md_view.override_background_color(Gtk.StateType.NORMAL, Gdk.RGBA(0.2,0.2,0.2, 1))
            #md_view.override_color(Gtk.StateType.NORMAL, Gdk.RGBA(0.9,0.9,0.9, 1))
            md_view.override_font(Pango.FontDescription("Monospace"))
            md_view.set_wrap_mode(Gtk.WrapMode.WORD )
            md_buffer = md_view.get_buffer()
            md_view.set_editable(False)
            md_scrl.add(md_view)
            md_buffer.set_text(md_text)

            notebook.append_page(md_scrl, Gtk.Label("Source Code"))


            
    except:
        pass

    # Channel Uploads / Publications
    
    if is_channel:

        uploads_box = Gtk.VBox()
        notebook.append_page(uploads_box, Gtk.Label("Publications"))
    
    
    ##### DESCRIPTION ####
    
    try:
        description_scrl = Gtk.ScrolledWindow()
        description_scrl.set_size_request(500,200)
        description_field = Gtk.TextView()
        description_field.set_wrap_mode(Gtk.WrapMode.WORD )
        description_field.set_editable(False)
        description_buffer = description_field.get_buffer()
        description_buffer.set_text(out["value"]["description"])
        markdown.convert(win, description_field)

        description_box = Gtk.VBox()
        notebook.append_page(description_scrl, Gtk.Label("Description"))
        
        description_box.pack_start(description_scrl, False, False, False)
        description_scrl.add(description_field)
    except:
        pass

    ##### Raw Data #######

    raw_scrl = Gtk.ScrolledWindow()
    raw_view = data_view.data_widget(out)
    raw_scrl.add(raw_view)
    notebook.append_page(raw_scrl, Gtk.Label("Raw Data"))
    
    outbox.show_all()
    return True



def downloaded(claim_id):

    # Returns a fraction ( from 0 to 1 ) of the download
    # percentage. If it's a 0, we can use it to display
    # the download button.

    out = check_output(["flbry/lbrynet",
                         "file", "list", "--claim_id="+claim_id])

    try:
        out = json.loads(out)
        out = out["items"][0]

        if out["status"] == "finished":
            return 1
        else:
            return out["written_bytes"] / out["total_bytes"]
        
    except:
        return 0

def get_downloaded_file(claim_id):

    out = check_output(["flbry/lbrynet",
                         "file", "list", "--claim_id="+claim_id])

    try:
        out = json.loads(out)
        out = out["items"][0]

        return out["download_path"]
    except:
        return ""

def delete_file(claim_id):
    check_output(["flbry/lbrynet",
                         "file", "delete", "--claim_id="+claim_id])
def start_downloading(url):
    check_output(["flbry/lbrynet",
                                    "get", url])
    
def downloading_check_thread(win, claim_id,
                             download_button,
                             delete_button,
                             launch_button,
                             progress_bar):

    # This is a thread that will toggle buttons on/off
    # based on a curretly downloading file.

    while True:
        fraction = downloaded(claim_id)

        if not fraction: # if it's 0
            download_button.set_visible(True)
            delete_button.set_visible(False)
            launch_button.set_visible(False)
            progress_bar.set_visible(False)
        else:
            download_button.set_visible(False)
            delete_button.set_visible(True)
            launch_button.set_visible(True)
            progress_bar.set_visible(True)
            progress_bar.set_fraction(fraction)
        if fraction == 1:
            progress_bar.set_visible(False)

        if not win.check_download_daemon_keep_alive:
            return
